﻿using System.Net.Http.Headers;
using System.Text;
using Dispatcher.Endpoints.Worker;
using Dispatcher.Models;
using Dispatcher.Models.Openai;
using Dispatcher.Models.Requests;
using Newtonsoft.Json;

namespace Dispatcher.Endpoints;

public class SimpleTransferEndpoint
{
    public async Task Endpoint(HttpContext context,DataContext data,KeyPoolRepository repository)
    {
        // 对请求的验证可以放置在中间件。
        var path = context.Request.RouteValues["path"]?.ToString();//额外请求路径
        var poolKey = (PoolKey)context.Items["PickedKey"];
        if (poolKey == null)
        {
            await Error();
            return;
        }
        async Task Error()
        {
            await context.Response.WriteAsync("服务器内部错误，找不到可用的池主机或者池key");
        }
        var baseUrl = "";
        if (poolKey.HandHosts != null)
        {
            baseUrl = poolKey.HandHosts;
        }
        else if(poolKey.AvailableHosts!=null)
        {
            baseUrl = poolKey.AvailableHosts[new Random().Next(poolKey.AvailableHosts.Count)];
        }
        else
        {
            await Error();
            return;
        }

        var url = baseUrl+"/v1/"+path;//拼接代理地址
        string requestBody;// 读取请求体
        using (var reader = new StreamReader(context.Request.Body))
        {
            requestBody = await reader.ReadToEndAsync();
        }

        await ContinueWithRaw(url, poolKey, requestBody, context, data, repository);

    }
    public static async Task ContinueWithRaw(string url,PoolKey poolKey,string requestBody,HttpContext context,
        DataContext data,KeyPoolRepository repository)
    {
        using var client = new HttpClient();
        var request = new HttpRequestMessage(HttpMethod.Post, url);// 构建请求
        client.DefaultRequestHeaders.Add("Authorization",$"Bearer {poolKey.Cipher}");
        request.Content = new StringContent(requestBody, Encoding.UTF8, "application/json");
        request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        // 添加请求体和请求头
        var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
        var contentStream = await response.Content.ReadAsStreamAsync();

        if ((int)response.StatusCode != StatusCodes.Status200OK&&(!(poolKey.PoolKeyId == long.MaxValue)))
        {
            var dk = data.PoolKeys.Where(p => p.PoolKeyId == poolKey.PoolKeyId).FirstOrDefault();
            if (dk != null)
            {
                repository.RemovePoolKey(dk);
                dk.Available = false;
            }

            await data.SaveChangesAsync();
        }
        try
        {
            if (!context.Response.Headers.ContainsKey("Content-Type"))
            {
                context.Response.ContentType =
                response.Content.Headers.ContentType.ToString();
            }
        }
        catch
        {//ignore

        }

        var buffer = new byte[50];
        int bytesRead;
        while ((bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
        {
            await context.Response.Body.WriteAsync(buffer, 0, bytesRead);
            await context.Response.Body.FlushAsync();
        }
    }
}